Title:
Course Schedule
Link to LeetCode:
https://leetcode.com/problems/course-schedule/
Specification:
There are a total of numCourses courses you have to take, labeled from 0 to numCourses-1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
Examples:
Example 1:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
Example 2:
Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take.To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
Initial Code and Signature:
public interface CycleDetectorInDAG {
public boolean canFinish(int numCourses, int[][] prerequisites) ;
}
Algorithm:
Main Idea: Courses can be finished if there is no cycle in the graph of the course dependencies.Run-Time Complexity Analysis
GitHub Project:
https://github.com/m-h-s/Algorithms-Codes/tree/master/35-CourseSchedule/src
Code:
import java.util.*;
/**
*
* @author Mahsa Sadi
*
* @since 2020 - 06 - 08
*
* License: Creative Commons
*
* Copyright by Mahsa Sadi
*
*/
public class CycleDetectorInDAGS2 implements CycleDetectorInDAG {
/**
* Problem: Course Schedule
*
*
* Description:
* There are a total of numCourses courses you have to take, labeled from 0 to numCourses-1.
* Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
* Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
*
*
* Solution:
* Main Idea: Courses can be finished if there is no cycle in the graph of the course dependencies.
* The solution should find and detect a cycle in a directed graph.
* If no such cycle exists, then the given courses can be finished.
* To find such cycle, we find nodes with inDegree of zero and remove these nodes and their related edges from the graph.
* We continue this process until all nodes are removed.
* If there is no node with inDegree of zero in the remaining graph, it means there is a cycle in the graph.
*
*
* Strategy 1:
*
* 1 - Consider a map or array of adjacency for the graph; i.e.; Map of >.
* The keys are source nodes and the values are destination nodes of the edges starting from the source.
*
* 2 - Consider a map or array of inDegrees for the graph; i.e; Map .
*
* 3- For each edge in the prerequisite array, update adjacency and inDegree tables.
*
* 4- Consider a counter for the number of nodes with inDegree of Zero.
*
* 5- Scan the inDegree Table, find all the nodes with inDegree of zero.
*
* 6- If no node with inDegree zero exists and the counter defined in step 4- is not equal to the total number of courses,
* return false; i.e.; there is a cycle in the graph.
*
* 7- Update the counter defined in step 4-.
*
* 8- Remove the nodes with inDegree of Zero and the edges starting from them by decreasing the inDegree of their neighbors.
*
* 9- Go to 5- and continue.
*
* 10- If the counter identified in 4- equals to the number of courses return true.
*
*
*/
ArrayList <Integer> [] graph;
int [] inDegrees;
boolean canBeFinished;
@Override
public boolean canFinish(int numCourses, int[][] prerequisites) {
if (prerequisites.length == 0)
canBeFinished = true;
else
{
graph = new ArrayList [numCourses];
inDegrees = new int [numCourses];
for (int i = 0; i < prerequisites.length; i++ )
{
int source = prerequisites [i][1];
int dest = prerequisites [i][0];
if (graph [source] == null)
graph [source] = new ArrayList <Integer> ();
graph [source].add(dest);
inDegrees [dest]++;
}
int counter = 0;
while (counter < numCourses)
{
List <Integer> nodesToBeRemoved = findDegreeZeros (numCourses);
if ( nodesToBeRemoved.isEmpty())
{
canBeFinished = false;
break;
}
counter += nodesToBeRemoved.size();
updateIndegrees (nodesToBeRemoved);
}
if ( counter == numCourses)
canBeFinished = true;
}
return canBeFinished;
}
List findDegreeZeros (int numCourses)
{
List <Integer> degreeZero= new ArrayList <Integer> ();
for (int i = 0 ; i < numCourses; i++ )
{
if ( inDegrees [i] == 0 )
{
degreeZero.add(i);
inDegrees [i] = -1;
}
}
return degreeZero;
}
void updateIndegrees (List <Integer> removedSourceNodes)
{
for (int i = 0; i < removedSourceNodes.size (); i++ )
{
ArrayList <Integer> dests = graph [removedSourceNodes.get(i)];
if (dests != null)
{
for (int j = 0; j < dests.size(); j++)
inDegrees [dests.get(j)]--;
}
}
}
}